6.4 Ereignisse in der Vererbung
 
In der Vererbungskette nehmen Ereignisse eine besondere Stellung ein. Um dies zu verdeutlichen, ist im folgenden Codefragment die Klasse ClassA definiert, die das Ereignis Hallo veröffentlicht.
| class ClassA {
|
| public delegate void MyHandler();
|
| public event MyHandler Hallo;
|
| public void DoSomething() {
|
| if(Hallo != null)
|
| Hallo();
|
| }
|
| }
|
Wie üblich wird ein Delegat definiert und anschließend das Ereignis vom Typ des Delegaten deklariert. Ausgelöst wird das Ereignis beim Aufruf von DoSomething. In der Methode Main der Klasse Program wird jetzt zu Testzwecken ein Objekt vom Typ der ClassA erzeugt und das Ereignis Hallo an den Ereignisempfänger MyTestMethod gebunden:
| class Program {
|
| static void Main(string[] args) {
|
| ClassA obj = new ClassA();
|
| obj.Hallo += new ClassA.MyHandler(MyTestMethod);
|
| obj.DoSomething();
|
| Console.ReadLine();
|
| }
|
| public static void MyTestMethod() {
|
| Console.WriteLine("Ereignis ist ausgelöst.");
|
| }
|
| }
|
Der Aufruf von DoSomething auf das ClassA-Objekt bewirkt, dass die vom Delegaten beschriebene Methode MyTestMethod ausgeführt und im Konsolenfenster
angezeigt wird.
Nun soll ClassB die Klasse ClassA ableiten. ClassB wird um die objektspezifische Methode RaiseEvent ergänzt, deren Aufruf ebenfalls die Auslösung des Ereignisses Hallo bewirkt. Unter der Annahme, dass sich ein Ereignis an die ableitende Klasse vererbt, kann die Auslösung des Ereignisses Hallo folgendermaßen implementiert werden:
| class ClassB : ClassA {
|
| public void RaiseEvent() {
|
| if(Hallo != null)
|
| Hallo();
|
| }
|
| }
|
Der Versuch der Kompilierung wird allerdings scheitern, weil die beiden Anweisungen in RaiseEvent einen Fehler verursachen. Der Fehlerbeschreibung des Compilers können wir entnehmen, dass der Bezeichner Hallo nicht erkannt wird. Selbst das Schlüsselwort base in der Anweisung
kann das nicht vermeiden. Der Grund dafür ist, dass Ereignisse immer an die Klasse gebunden sind, in der sie definiert sind.
| Ein Ereignis kann nur in der ereignisdefinierenden Klasse ausgelöst werden und nicht in einer abgeleiteten Klasse.
|
Damit stellt sich die Frage, wie wir das Ereignis einer Basisklasse einer abgeleiteten Klasse zur Verfügung stellen können.
Die Lösung ist sehr einfach: Wir implementieren eine zusätzliche Methode in der Klasse, in der das Ereignis definiert ist. In dieser Methode lösen wir das Ereignis aus. In unserem Beispiel müssten wir demnach die Klasse ClassA wie folgt ergänzen bzw. ändern:
| class ClassA {
|
| public delegate void MyHandler();
|
| public event MyHandler Hallo;
|
| public void DoSomething() {
|
| // -------- Änderung --------
|
| OnHallo();
|
| }
|
| // -------- Neu --------
|
| public void OnHallo() {
|
| if(Hallo != null)
|
| Hallo();
|
| }
|
| }
|
Die Methode OnHallo berücksichtigt jetzt die Bedürfnisse einer ableitenden Klasse. In OnHallo wird das Ereignis Hallo ausgelöst, was keine Komplikationen mehr verursacht, da das Ereignis in derselben Klasse definiert ist. Außerdem wird die Methode OnHallo nun auch aus der Methode DoSomething heraus aufgerufen, was allerdings nicht zwingend notwendig ist.
Kommen wir zurück zur abgeleiteten Klasse ClassB. In Kenntnis der Methode OnHallo sollte die Anweisung in der Methode RaiseEvent wie folgt aussehen:
| class ClassB : ClassA {
|
| public void RaiseEvent() {
|
| this.OnHallo();
|
| }
|
| }
|
Das Ereignis wird nicht mehr direkt aufgerufen, sondern die geerbte Methode OnHallo, die ihrerseits die Ereignisauslösung richtig delegiert.
Sehen wir uns zum Abschluss den zusammengefassten Code an.
| // --------------------------------------------------------------
|
| // Beispiel: ...\Kapitel 6\Ereignisse
|
| // --------------------------------------------------------------
|
| class Program {
|
| static void Main(string[] args) {
|
| ClassB obj = new ClassB();
|
| obj.Hallo += new ClassB.MyHandler(MyTest);
|
| obj.RaiseEvent();
|
| Console.ReadLine();
|
| }
|
| public static void MyTest() {
|
| Console.WriteLine("Ereignis ist ausgelöst.");
|
| }
|
| }
|
| // ----- Basisklasse -----
|
| class ClassA {
|
| public delegate void MyHandler();
|
| public event MyHandler Hallo;
|
| public void DoSomething() {
|
| OnHallo();
|
| }
|
| public void OnHallo() {
|
| if(Hallo != null)
|
| Hallo();
|
| }
|
| }
|
| // ----- abgeleitete Klasse -----
|
| class ClassB : ClassA {
|
| public void RaiseEvent() {
|
| this.OnHallo();
|
| }
|
| }
|
|